#!/usr/sbin/rsct/perl5/bin/perl 
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 1999,2002 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# "@(#)63   1.15   src/rsct/registry/cli/bin/mksrfile.perl, srcli, rsct_rpyxh, rpyxht1f3 2/22/01 16:25:45"
######################################################################
#                                                                    #
# Module: mksrfile                                                   #
#                                                                    #
# Purpose:                                                           #
#   mksrfile - Make (store) a file in the System Registry.           #
#                                                                    #
# Syntax:                                                            #
#   mksrfile [-h][-TV] AIX_filename [SR_filename]                    #
#                                                                    #
# Flags:                                                             #
#   -h Help. Writes this command's usage statement to stdout.        #
#   -T Trace. Writes this command's trace messages to stderr.        #
#   -V Verbose. Writes this command's verbose messages to stderr.    #
#                                                                    #
# Operands:                                                          #
#   AIX_filename Name of the file to be stored in the System         #
#                Registry.                                           #
#                                                                    #
#   SR_filename Optional  - Name of the System Registry table where  #
#               the AIX file will be stored.  The operand can        #
#               contain an absolute or relative path.                #
#                                                                    #
# Description:                                                       #
#   The mksrfile command reads in and stores a file AIX_filename     #
#   as binary data to a newly created System Registry table          #
#   SR_filename. The new table will have 10 columns, a primary key   #
#   column, the file name prefixed by it's entire path , modification#
#   date, access date, permissions, UID and GID from AIX, the type   #
#   (binary or text,) a standard B-qualified (binary) column         #
#   containing a binary image of the file, and the system-generated  #
#   row change counter column. The size of the file (the bit count)  #
#   is stored with the image.                                        #
#                                                                    #
#   If SR_filename is omitted, then the System Registry table name   #
#   will become AIX_filename. In this case, the path is stripped     #
#   from AIX_filename (if applicable) and the current directory as   #
#   set using the CT_SR_HOME environment variable is used as the     #
#   parent directory for the new table. The parent directory of the  #
#   new file must already exist in the System Registry. Tables must  #
#   be unique to a directory. Use the lssr (srls) command to list    #
#   existing tables and directories.                                 #
#                                                                    #
#   AIX_filename can be binary or text.  If it is a text file, it is #
#   not stored in a readable format in the System Registry.          #
#                                                                    #
# Exit Values:                                                       #
#   0  SR_CLI_SUCCESS        Command completed successfully.         #
#   1  SR_CLI_REGISTRY_ERROR Command terminated due to an underlying #
#                            System Registry error.                  #
#   2  SR_CLI_ERROR          Command terminated due to an underlying #
#                            error in the command script.            #
#   3  SR_CLI_BAD_OPERAND    Command terminated due to user          #
#                            specifying a bad operand.               #
#   4  SR_CLI_BAD_FLAG       Command terminated due to user          #
#                            specifying an invalid flag.             #
#   5  SR_CLI_USER_ERROR     Command terminated due to a user error. #
#                            For example specifying an undefined     #
#                            directory to be used.                   #
#                                                                    #
# Examples:                                                          #
#   1. To save the file /tmp/hosts to the System Registry table      #
#   /samples/hosts_file, enter:                                      #
#     mksrfile /tmp hosts /samples/hosts_file                        #
#                                                                    #
#   2. To save the file hosts from the current AIX working directory #
#   to the table hosts_file in the current System Registry working   #
#   directory, assuiming the CT_SR_HOME is set to /samples, enter:   #
#      mksrfile hosts hosts_file                                     #
#                                                                    #
#--------------------------------------------------------------------#
#                                                                    #
# Inputs:                                                            #
#   user input from command line or file                             #
#                                                                    #
# Outputs:                                                           #
#   stdout - progress and/or Verbose messages                        #
#   stderr - error messages                                          #
#                                                                    #
#                                                                    #
# External Ref:                                                      #
#   Commands: $LSMSG                                                 #
#   Extensions:  SR.pm                                               #
#   Perl library routines: Getopts::Std                              #
#   CLI library routines:                                            #
#           SR_column_utils - make_col_struct process_input_file     #
#           SR_display_utils = hex2bin                               #
#           SR_utils - init_session isRelative                       #
#                      printCEMsg clean_session                      #
#                                                                    #
# Tab Settings:                                                      #
#   4 and tabs should be expanded to spaces before saving this file. #
#   in vi:  (:set ts=4  and   :%!expand -4)                          #
#                                                                    #
# Change Activity:                                                   #
#   000900 HGJ 38317: Initial delivery.                              #
#                                                                    #
######################################################################

#--------------------------------------------------------------------#
# General Program Flow/Logic:                                        #
#                                                                    #
# A: Parse command line - get table name and input file              #
# B: Initialise session with registry, including changing the        #
#    current directory if a relative path name is given (use value   #
#    given in CT_SR_HOME.)                                           #
# C: Parse input file, if necessary. Create column data to be fed    #
#    into CT::SR::create_table.                                      #
# D: Call CT::SR::create_table to create table if possible           #
# E: Create row data to be fed into CT::SR::add_rows                 #
# F: Call CT::SR::add_rows extension                                 #
# G: Clean up session table and tree                                 #
#                                                                    #
#--------------------------------------------------------------------#

#--------------------------------------------------------------------#
# Included Libraries and Extensions                                  #
#--------------------------------------------------------------------#
use lib "/usr/sbin/rsct/pm";
use locale;
use Getopt::Std;
use Cwd;                                # Access to cwd command,   
                                        # to pick up current working
                                        # directory

use CT::CT qw(:ct_data_type_t);
use CT_cli_utils qw(printIMsg
                    printEMsg
);
use CT_cli_input_utils qw(convert_input_value);

use CT::SR;
use CT::SRrc;
use CT::SR qw(:sr_qualifier_t);
use SR_cli_utils qw(init_session 
                    isRelative 
                    printCEMsg
                    $DEFAULT_GLOBAL_MOUNT_POINT
                    clean_session
                    error_exit
);
use SR_cli_rc qw(:return_codes);


#--------------------------------------------------------------------#
# Global Variables                                                   #
#--------------------------------------------------------------------#
# Constants
$TRUE           = 1;
$FALSE          = 0;

# This number is one less than the final value because the 
# Registry adds 1 more column - the row change counter
$NUM_COLUMNS    = 9;

# Other globals    
$Verbose        = $FALSE;               # set if -V used
$Trace          = $FALSE;               # set if -T used 

# Messaging Variables
$PROGNAME       = "mksrfile";           # Program Name for messages
$MSGCAT         = "srcli.cat";          # msg catalogue for this cmd
$CTDIR          = "/usr/sbin/rsct";     # Cluster directory path
$CTBINDIR       = "$CTDIR/bin";         # Cluster Bin directory path
$LSMSG          = "$CTBINDIR/ctdspmsg"; # Display message routine
$ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps";  # Msg maps path for$LSMSG  

%Cleanup = ();                          # Hash of items to cleanup
                                        # {Session} $session to term

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
my $Tree_handle    = "";
my $New_table      = CT::SR::table_handle_t->new;  
my @Fields = ();
my @Field_types = ();
my @Columns = ();
my @New_fields = ();

my $AIX_filename   = "";
my $SR_filename    = "";
my $Data_filename  = "";

my $Set_work_dir   = $FALSE;
my $Buffer         = "";
my $Buf            = "";

my $rc             = 0;                    # assume good return code

my $Mount_point    = $DEFAULT_GLOBAL_MOUNT_POINT;


#--------------------------------------------------------------------#
# Main Code                                                          #
#--------------------------------------------------------------------#
# TODO: Many verbose statements in this code will eventually by
# Trace statements when the facility is available as a Perl CLI
# (feature 48401)
# TODO: security on access to the table can not be further defined
# until after a security design has been implemented for the SR.
# ( feature 48402 ) Until then, the table is opened with the
# minimum security necessary to complete the command.

# Parse the command line, exit if there are errors
($rc, $AIX_filename, $SR_filename) = parse_cmd_line();  

# parse_cmd_line handles all its own error messages and returns
# it's local return code. So exit immediately if rc != 0
($rc == 0) || error_exit($rc); 


# $SR_filename not existing or being relative is the
# condition for setting the current working
# directory in the registry. Given this, the library
# connection can be established

if (($SR_filename eq "") or (isRelative($SR_filename))) {
        $Set_work_dir= $TRUE;
}


# Prepare the new table name
if ($SR_filename eq "") { 
    # In this case, the filename is considered relative
    $SR_filename = $AIX_filename;   
    $Table_name = $AIX_filename;

    # Strip off any path, leaving only the base file name
    $Table_name =~ s/^.*\/(.*)$/$1/;
}
else {
    if (isRelative($SR_filename)) {
        $Table_name = $SR_filename;
    }
    else {$Table_name = $Mount_point.$SR_filename;}
}

# The $AIX_filename to be opened can be take as is from
# the command line, as the open statement will
# support ../, ./, and such forth. 
# The file name stored with the data is fully qualified,
# however.

if (isRelative($AIX_filename)) {
    $AIX_current_working_directory = cwd();
    $Data_filename = $AIX_current_working_directory.'/'.$AIX_filename;
}


# Check to make sure the input file exists
if (!(-e $AIX_filename)) {
    printCEMsg("EMsgSRcliInvalidFileName", $AIX_filename);
    exit SR_CLI_BAD_OPERAND;
}


# Check to see if the file is binary - TODO: when the Perl 'pack'
# problem is deciphered (see below) then this flag will be
# uncommented
#if (-B $AIX_filename) {
#   printEMsg("EMsgmksrfileBinaryFile", $AIX_filename);
#   exit SR_CLI_BAD_OPERAND;    
#   $is_binary = $TRUE;
#}


# Make sure the the input filename can be opened, then pull 
# in the file
if (!open(FH, $AIX_filename)) { 
    printCEMsg("EMsgSRcliCannotOpenFile", $AIX_filename);
    exit SR_CLI_ERROR;
}

# After all that is done and okayed, then go ahead and establish
# a registry session
($rc,$Tree_handle) = init_session($Set_work_dir);
($rc == 0) || error_exit($rc); 

# Add the tree handle to the cleanup hash
$Cleanup{Session} = $Tree_handle;


# Grab the stats on the opened file to get the uid, gid,
# etc. Check the Ram Cookbook for info on this.
($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
    $atime, $mtime, $ctime, $blksize, $blocks) = stat FH;

# This works to save the permissions. 
$mode &= 07777; # discards the file type information

# Pull out the uid and gid from the mode information
($s, $user, $group, $other) = (($mode & 07000)>>9, ($mode & 0700)>>6, ($mode & 0070)>>3, $mode & 0007);


$Verbose && print STDERR "user perms: $user\n";
$Verbose && print STDERR "group perms: $group\n";
$Verbose && print STDERR "other perms: $other\n";

$permissions = $s.$user.$group.$other;
$Verbose && print STDERR "permissions: $permissions\n";


# Read the file contents into a buffer
$count = 0;
$Buf = "";

while (read(FH, $Buffer, 8 * 2**10)) {
    $count++;
    $Buf .= $Buffer;
}   
$Verbose &&  print STDERR  "picked up $count lines \n";

# Convert the input to binary. Assume ascii unless otherwise
# mentioned? - Start with Ascii at any rate

# "A*" works for text files. "B*" should work for binary files
# but not in this release
# TODO: Binary unpack wants to even out an odd byte count (try
# the perl executable forexample.) so it comes out the incorrect size.
#if ($is_binary) { $Binary_image = pack("B*", $Buf);}
#else { $Binary_image = pack("A*", $Buf); }

#$Binary_image = pack("A*", $Buf); 


# Save the length of the image to store
#$Packed_length = length($Binary_image);
#$Verbose && print STDERR "packed length: $Packed_length\n";



# Here is where the file gets made - see details in the Description
# in the prolog for what is in the table
# Construct the new table

@Column_list = ();

# Create the primary key column
$Column_list[0]->{name} = "Key";
$Column_list[0]->{type} = CT_UINT32;
$Column_list[0]->{qualifier} = SR_PRIMARY_KEY;
$Column_list[0]->{properties} = 0;
$Column_list[0]->{default} = 0;

# Set the file name column - this couldn't be the primary key,
# otherwise it couldn't be updated if/when the file was replaced

$Column_list[1]->{name} = "FileName";
$Column_list[1]->{type} = CT_CHAR_PTR;
$Column_list[1]->{qualifier} = SR_STANDARD;
$Column_list[1]->{properties} = 0;
$Column_list[1]->{default} = "AIX input file name";

$Column_list[2]->{name} = "ModificationDate";
$Column_list[2]->{type} = CT_CHAR_PTR;
$Column_list[2]->{qualifier} = SR_STANDARD;
$Column_list[2]->{properties} = 0;
$Column_list[2]->{default} = "";

$Column_list[3]->{name} = "LastAccessDate";
$Column_list[3]->{type} = CT_CHAR_PTR;
$Column_list[3]->{qualifier} = SR_STANDARD;
$Column_list[3]->{properties} = 0;
$Column_list[3]->{default} = "";

$Column_list[4]->{name} = "Permissions";
$Column_list[4]->{type} = CT_CHAR_PTR;
$Column_list[4]->{qualifier} = SR_STANDARD;
$Column_list[4]->{properties} = 0;
$Column_list[4]->{default} = "";

$Column_list[5]->{name} = "UID";
$Column_list[5]->{type} = CT_CHAR_PTR;
$Column_list[5]->{qualifier} = SR_STANDARD;
$Column_list[5]->{properties} = 0;
$Column_list[5]->{default} = "";

$Column_list[6]->{name} = "GID";
$Column_list[6]->{type} = CT_CHAR_PTR;
$Column_list[6]->{qualifier} = SR_STANDARD;
$Column_list[6]->{properties} = 0;
$Column_list[6]->{default} = "";

$Column_list[7]->{name} = "Type";
$Column_list[7]->{type} = CT_CHAR_PTR;
$Column_list[7]->{qualifier} = SR_STANDARD;
$Column_list[7]->{properties} = 0;
$Column_list[7]->{default} = "";


# Create the (binary) data column       
$Column_list[8]->{name} = "FileData";
$Column_list[8]->{type} = CT_BINARY_PTR;
$Column_list[8]->{qualifier} = SR_STANDARD;
$Column_list[8]->{properties} = 0;
$Column_list[8]->{default} = 
    convert_input_value(CT_BINARY_PTR, "0x00000000");


$Verbose && 
   printIMsg("IMsgmksrfileStoringFile", $Table_name ); 

$Trace && print STDERR "Calling CT::SR::create_table\n";
$rc = CT::SR::create_table($Tree_handle, $Table_name, \@Column_list, 
                        $New_table);
$Trace && print STDERR "CT::SR::create_table return code $rc\n";

$Verbose && CT::SR::dump_table($New_table);

$rc = error_check("sr_create_table", $rc, $AIX_filename, 
    $SR_filename, $Table_name);

# Even if SR::create_table failed, clean up session -
# Exit with the least non-zero return code
($rc == 0) || error_exit($rc);


push @{$Cleanup{Tables}}, $New_table;

# Add the data row to the table

# Set up the data fields
@Fields = (2001, $Data_filename, $mtime, $atime, $permissions,
            $uid, $gid);

$Fields[7] = "text";

$Binary->{length} = length($Buf);
$Binary->{image} = $Buf;

$Fields[8] = $Binary;


# Set up the field types array - list of the data type of each field
@Field_types = (CT_UINT32, CT_CHAR_PTR, CT_CHAR_PTR, 
                CT_CHAR_PTR, CT_CHAR_PTR, CT_CHAR_PTR, 
                CT_CHAR_PTR, CT_CHAR_PTR, CT_BINARY_PTR);


# Set up the column names
@Columns = ("Key", "FileName", "ModificationDate",
            "LastAccessDate", "Permissions", "UID",
            "GID", "Type", "FileData");

# Set up the data structure to be passed into add_row
@New_fields = ([@Fields], [@Field_types], 9);

$Trace && print STDERR "Calling CT::SR::add_row\n";
$rc = CT::SR::add_row($New_table, \@Columns, \@New_fields);

$Trace && print STDERR "CT::SR::add_row return code: $rc\n";

$Verbose && CT::SR::dump_table($New_table);

$rc = error_check("sr_add_row", $rc, $AIX_filename, $SR_filename, 
    $Table_name);
($rc == 0) || error_exit($rc); 


# Exit with the least non-zero return code
$rc = clean_session($Tree_handle, $Mount_point, $New_table );
($rc == 0) || error_exit($rc); 

exit $rc;


#--------------------------------------------------------------------#
# End Main Code                                                      #
#--------------------------------------------------------------------#
    
#--------------------------------------------------------------------#
# parse_cmd_line:                                                    #
#   Uses getopts() to grab flags on the command line, parses out the #
#   file names provided on the command line.                         #
#                                                                    #
# Parameters:                                                        #
#                                                                    #
# Return values:                                                     #
#   $local_rc - return code 0 if ok, > 0 if error                    #
#   $AIX_file - AIX filename to be read in and stored                #
#   $SR_file - table name to be created                              #
#                                                                    #
# Global variables modified:                                         #
#   $opt_T, $opt_h, $opt_V - by getopts                              #
#   $Verbose - if $opt_V is set                                      #
#   $Trace   - if $opt_T is set                                      #
#   @ARGV - command line input read from here                        #
#                                                                    #
#--------------------------------------------------------------------#
sub parse_cmd_line
{
my $file_name = ""; 
my $local_rc = 0;
my $AIX_file= "";
my $SR_file = "";
my %opts = ();

if (getopts('hTV', \%opts) == 0) {        # parse input flags
    printCEMsg("EMsgSRcliInvalidFlag");
    print_usage();
    return SR_CLI_BAD_FLAG;         # error parsing command line
}     
              
if (defined $opts{h}) {             # print usage and exit
    print_usage();
    exit(0);    # success but quit
}
   
# Set Trace flag if requested 
if (defined $opts{T}) {
    $Trace = $TRUE;
}
    
# Set Verbose flag if requested 
if (defined $opts{V}) {
    $Verbose = $TRUE;
}

# Grab the AIX filename, if there 
if (@ARGV) { 
    $AIX_file = shift @ARGV;
}
else { 
    printCEMsg("EMsgSRcliFileNameMissing");
    print_usage();
    return SR_CLI_BAD_OPERAND;
}

# Grab the SR table name, if there
if (@ARGV) { 
    $SR_file = shift @ARGV;
}
else { 
    $SR_file = ""; 
}

return ($local_rc, $AIX_file, $SR_file);
};  # end parse_cmd_line


#--------------------------------------------------------------------#
# error_check:                                                       #
#   Checks the return code from the SR function.  If an error is     #
#   detected appropriate error messages will be displayed and        #
#   SR CLI return code set.                                          #
#                                                                    #
# Parameters:                                                        #
#   $sr_function  - Name of the SR function that was called and      #
#                   whose error code we are checking.                #
#   $sr_rc        - SR function return code.                         #
#   $aix_filename - Name of the aix file copying into a table.       #
#   $sr_filename  - (optional) Name of the SR table where the file   #
#                   is kept.                                         #
#   $table_name   - Name of the table trying to create.              #
#                                                                    #
# Return values:                                                     #
#   None.                                                            #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub error_check
{
my ($sr_function, $sr_rc, $aix_filename, $sr_filename, 
    $table_name) = @_;

if ($sr_rc != 0) {
    # The bulk of the create_table errors shouldn't occur
    # unless the code is somehow messed up, so none of this
    # is going to be the user's fault.
    # The errors reported here are possibly the user's
    # responsibility.
    if ($sr_rc == SR_NO_PERMISSION) {
        printEMsg("EMsgmksrfileNoPermission", $sr_filename);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_NO_DIRECTORY) {
        printCEMsg("EMsgSRcliNoDirectory", $sr_filename);
        $rc = SR_CLI_USER_ERROR;
    }
    elsif ($sr_rc == SR_TABLE_EXISTS) {
        printEMsg("EMsgmksrfileTableExists", $sr_filename);
        $rc = SR_CLI_USER_ERROR;
    }
    else {
        printEMsg("EMsgmksrfileErrorMakingFile", $aix_filename,
            $table_name);
        printCEMsg("EMsgSRcliSRCommandFailure", $sr_function, $sr_rc);
        $rc = SR_CLI_REGISTRY_ERROR;
    }
}

return ($rc);
}   # end error_check


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#   See this command's prologue syntax section for current usage.    #
#--------------------------------------------------------------------#
sub print_usage
{
printIMsg("IMsgmksrfileUsage");
}   # end print_usage


#--------------------------------------------------------------------#
# End File                                                           #
#--------------------------------------------------------------------#
